// sleepLine.js
export class SleepWaveLine {
  _parent = null
  // 动画属性
  drawerIndex = 0
  drawerSeg = 0 // 绘制直线时Y轴每次绘制长度
  linearGradient = '' // 渐变色
  lineX = 0 // 连线X位置
  lineStartY = 0 // 最终的Y位置
  lineEndY = 0 // 最终的Y位置
  dir = true // 0: 一样高（这种情况理论不应该存在）,true: 从下到上，false：从上到下
  preCurveSegX = 0 // 与上一个block连接的三角，绘制时的X轴方向每次绘制长度
  curveSegX = 0 // 当前block绘制三角时X轴方向每次绘制长度
  curveSegY = 0 // 绘制三角时Y轴方向每次绘制长度
  idealCurveRadius = 0 // 理想的圆弧

  constructor (canvas, opts) {
    this._parent = canvas
    this.ctx = canvas.ctx
    Object.assign(this, opts)
  }

  draw () {
    const { startX, startY, endY, pre, nowType, nowRadius } = this
    const { disY, types, blockHeight, animation, drawerFrequency, borderRadius, colors } = this._parent
    this.drawerIndex = animation ? 0 : drawerFrequency
    this.lineX = startX // 连线X位置

    // 需要判断是从下到上还是从上到下，注意canvas Y轴是上小下大，这里的上下是视觉的上下
    this.dir = pre[1] < nowType // 0: 一样高（这种情况理论不应该存在）,true:从下到上，false：从上到下
    // start到end是从左到右
    this.lineStartY = this.dir ?
      ((types.length - pre[1] - 0.5) * disY - borderRadius - blockHeight / 2) :
      ((types.length - pre[1] - 0.5) * disY + borderRadius + blockHeight / 2) // 连线起点Y
    this.lineEndY = this.dir ? endY : startY// 连线终点Y
    this.linearGradient = this.ctx.createLinearGradient(this.lineX, this.lineStartY, this.lineX, this.lineEndY) // 线的渐变色
    this.linearGradient.addColorStop(0, colors[pre[1]])
    this.linearGradient.addColorStop(1, colors[nowType])

    this.drawerSeg = Math.abs(this.lineEndY - this.lineStartY) / drawerFrequency / 2
    this.preCurveSegX = pre[2] / drawerFrequency
    this.curveSegX = nowRadius / drawerFrequency
    this.curveSegY = borderRadius / drawerFrequency
    this.idealCurveRadius = (disY - blockHeight) / 2
    // 先画直线
    this.drawLineOneTime()
  }

  // 绘制直线
  drawLineOneTime() {
    const { drawerFrequency, borderRadius, animation } = this._parent
    if (this.drawerIndex > drawerFrequency) {
      // 直线画完了，重置drawerIndex开始画曲线
      this.drawerIndex = animation ? 0 : drawerFrequency
      this.drawCurveLine()
      return
    }

    const dis = this.drawerSeg * this.drawerIndex
    const startY = (this.lineStartY + this.lineEndY) / 2 + (this.dir ? dis : -dis)
    const endY = (this.lineStartY + this.lineEndY) / 2 + ((this.dir ? -dis : dis))

    this.ctx.beginPath()
    this.ctx.lineWidth = this.lineWidth
    this.ctx.strokeStyle = this.linearGradient
    this.ctx.moveTo(this.lineX, startY)
    this.ctx.lineTo(this.lineX, endY)
    this.ctx.stroke()

    this.drawerIndex += 1
    requestAnimationFrame(() => this.drawLineOneTime())
  }

  // 绘制曲线
  drawCurveLine() {
    const { drawerFrequency, animation, borderRadius, lineWidth } = this._parent
    if (this.drawerIndex > drawerFrequency) {
      return
    }
    const { lineX, pre, dir, nowRadius, lineStartY, lineEndY, preCurveSegX, curveSegX, curveSegY, linearGradient, idealCurveRadius } = this

    // start左三角
    const curveStartLineX = lineX + lineWidth / 2
    this.ctx.beginPath()
    this.ctx.lineWidth = lineWidth / 2
    this.ctx.strokeStyle = linearGradient
    this.ctx.moveTo(curveStartLineX, lineStartY + (dir ? -idealCurveRadius  : idealCurveRadius))
    this.ctx.quadraticCurveTo(
      curveStartLineX, lineStartY + (dir ? -lineWidth / 2 : lineWidth / 2),
      curveStartLineX - preCurveSegX * this.drawerIndex, lineStartY + (dir ? -lineWidth / 2 : lineWidth / 2)
    )
    this.ctx.quadraticCurveTo(
      curveStartLineX, lineStartY + (dir ? curveSegY * this.drawerIndex / 2 : -(curveSegY * this.drawerIndex) / 2),
      curveStartLineX, lineStartY + (dir ? curveSegY * this.drawerIndex : -(curveSegY * this.drawerIndex))
    )
    this.ctx.closePath()
    this.ctx.fillStyle = linearGradient
    this.ctx.fill()

    // end右三角
    const curveEndLineX = lineX - lineWidth / 2
    this.ctx.beginPath()
    this.ctx.lineWidth = lineWidth / 2
    this.ctx.strokeStyle = linearGradient
    this.ctx.moveTo(curveEndLineX, lineEndY + (dir ? idealCurveRadius : -idealCurveRadius))
    this.ctx.quadraticCurveTo(
      curveEndLineX, lineEndY + (dir ? lineWidth / 2 : -lineWidth / 2),
      curveEndLineX + curveSegX * this.drawerIndex, lineEndY + (dir ? lineWidth / 2 : -lineWidth / 2)
    )
    this.ctx.quadraticCurveTo(
      curveEndLineX, lineEndY + (dir ? -curveSegY * this.drawerIndex / 2 : curveSegY * this.drawerIndex / 2),
      curveEndLineX, lineEndY + (dir ? -curveSegY * this.drawerIndex : curveSegY * this.drawerIndex)
    )
    this.ctx.closePath()
    this.ctx.fillStyle = linearGradient
    this.ctx.fill()

    this.drawerIndex += 1
    requestAnimationFrame(() => this.drawCurveLine())
  }
}
